package search2;

import env.Action;
import env.Enviroment;
import env.Tile;
import java.util.LinkedList;
import java.util.List;

/*************************************************************
 * ************************************************************
 * NOTE: FOR NOW, g=depth always!!!
 * @author user
 *************************************************************
 *************************************************************/
public class Node2 {
    static int counter=0;
    
    int id;
    private Node2 parent;
    private Action action; //what got me here?
    // FullState:
    private State2 state;
    private int depth;
    int g; //path cost FOR NOW, g=depth always!!!
    int h; //heuristic
    int f; //only for A*
    int remaining;

    public Node2(Node2 parent, Action action, int depth, int g, State2 state) {
        this.parent = parent;
        this.action = action;
        this.depth = depth;
        this.g = g;
        this.state=state;
        
        this.id=counter++;
        
        this.remaining=state.getFlags().size();
        h=h1();
        if(state.isAlive) {
             h+=(remaining>1?remaining:0);
        }
        else {
            h+=Enviroment.FLAG_REWARD*remaining; //punishment for death!
          // System.err.println("oi");
        }
        f=h+g;
        //System.out.println("created " +this);
    }

    public void getActionPath(LinkedList<Action> plan) {
        String s="";
        int j=18;
        for (Node2 i = this; i.parent != null; i = i.parent) {
            s=j+")\t"+i+" ->\n"+s;
            j--;
            plan.addFirst(i.action);
        }
        System.out.println("node path:\n" +s);
    }

    public int getDepth() {
        return depth;
    }

    public int getG() {
        return g;
    }
    
    public State2 getState() {
        return this.state;
    }
    
    public int remainingFlags(){
        return remaining;
    }
    


       //h(n) = manhattan distance from nearest flag.
    private int h1() {
        if(remaining==0) //BUG FIX:  if it's 0, h1() will return MAX_VALUE
            return 0;
        int d = Integer.MAX_VALUE;
        //int row=getRow(), col=getCol();
        Tile current=state.getTile();
        for (Tile flag : getState().getFlags()) {
            int temp = current.manhattan(flag);
            if (temp < d) {
                d = temp;
            }
        }
        return d;
    }
 
    

    //returns 0 to 3 new nodes
    public List<Node2> expand() {
        List<Node2> ans = new LinkedList<Node2>();
        
        if(!state.isAlive)
            return ans; //no moves for the dead man...
        
        State2 fwd=state.clone(action.fwd);
        if (!fwd.getTile().isWall() ){//&&
                //to stop sentry collisions:
//                (state.getSentry()==null || fwd.getRow()!=state.getSentry().getRow() || fwd.getCol()!=state.getSentry().getCol())) { 
                 ans.add(new Node2(this, action.fwd, depth + 1, g + 1, fwd)); //F
        }
        //Can't turn on ice:
        if (!state.getTile().isIce()) {
            ans.add(new Node2(this, action.left, depth + 1, g + 1, state.clone(action.left))); //L
            ans.add(new Node2(this, action.right, depth + 1, g + 1, state.clone(action.right))); //R
        }
        
        return ans;
    }


    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Node2 other = (Node2) obj;
        if (this.state != other.state && (this.state == null || !this.state.equals(other.state))) {
            return false;
        }
        return true;
    }
    
    @Override
    public int hashCode() {
        return state.hashCode();
    }
    

    @Override
    public String toString() {
        return "node #"+id+" after "+action+" from #"+(parent==null?"":parent.id)+"\tg="+g+", h="+h+", f="+(g+h)+", "+state;
    }
    
    
    

}
